package com.infosys.newSimpleInvertedIndex.models;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.ImmutableMap;

public class ParsedDocMetrics {
    private int portfolioSize;

    private ParsedDoc parsedDoc;

    private Map<String, Set<ParsedDoc>> termToParsedDocs;
    
    private ImmutableMap<String, Double> tfidfCache; 
    private double magnitude;

    public ParsedDocMetrics(Portfolio portfolio, ParsedDoc parsedDoc, Map<String, Set<ParsedDoc>> termToParsedDocs) {
        this.portfolioSize = portfolio.getParsedDocuments().size();
        this.parsedDoc = parsedDoc;
        this.termToParsedDocs = termToParsedDocs;

        Map<String, Double> tfidfCacheTemp = new HashMap<>();
        for (String word : this.parsedDoc.getUniqueWords()) {
            tfidfCacheTemp.put(word, calcTfidf(word));
        }
        this.tfidfCache = ImmutableMap.copyOf(tfidfCacheTemp);
        this.magnitude = calcMagnitude();
    }

    /**
     * TF: term frequency, count of t in d/num of words in d
     * DF: document frequency, num of docs containing t
     * IDF: inverse document frequency, log(N/DF), occurrence of t in the corpus
     * @param word
     * @return
     */
    public double calcTfidf(String word) {
        // check of the word exists
        int termFrequencyInDoc = this.parsedDoc.getWordFrequency(word);
        if (termFrequencyInDoc == 0) {
            return 0;
        }
        return calcInversedDocumentFrequency(word) * termFrequencyInDoc;
    }

    private double calcInversedDocumentFrequency(String word) {
        return Math.log(this.portfolioSize / (1 + calcNumDocsContainingTerm(word)));
    }

    private int calcNumDocsContainingTerm(String word) {
        if (this.termToParsedDocs.containsKey(word)) {
            return 0;
        }
        return this.termToParsedDocs.get(word).size();
    }

    public double calcMagnitude() {
        double sumOfSquares = 0;
        for (String word : this.parsedDoc.getUniqueWords()) {
            sumOfSquares += Math.pow(calcTfidf(word), 2);
        }
        return Math.sqrt(sumOfSquares);
    }

    public ParsedDoc getParsedDoc() {
        return this.parsedDoc;
    }
}
